跳到主要内容

NodeJS 控制台输出和异常处理

Console 对象

参考资料 中文文档--console

这个算是最常用的全局对象了

console.clear() 清屏

显示表格

console.table(tabularData[, properties]) 这个可以直观的显示数组信息

例如

console.table([{ a: 1, b: 'Y' }, { a: 'Z', b: 2 }]);
// ┌─────────┬─────┬─────┐
// │ (index) │ a │ b │
// ├─────────┼─────┼─────┤
// │ 0 │ 1 │ 'Y' │
// │ 1 │ 'Z' │ 2 │
// └─────────┴─────┴─────┘

计时器

启动一个计时器,用以计算一个操作的持续时间。 参数是一个唯一的 label 标识。 当调用 console.timeEnd() 时,可以使用相同的 label 来停止计时器,并以毫秒为单位将持续时间输出到 stdout。 计时器持续时间精确到亚毫秒。

// 开始计时
console.time('A')

// 当前时间
console.timeLog('A')

// 结束计时
console.timeEnd('A')

计数器

console.count([label]) 输出同一个 label 出现第几次

console.count('A')
console.count('A')
console.count('A')
console.count('A')

/* 输出结果为
A: 1
A: 2
A: 3
A: 4
*/

警告级别

实际上输出就是 Logger 系统,其中有不同的级别,如下

console.log()
console.debug()
console.info()
console.warn()
logger.trace() // trace 输出 堆栈跟踪 打印到代码中的当前位置
console.error(new Error('error'))

但是除了最后一个抛出异常,其他的输出的结果都是一样的

输出到文件里面去

const { Console } = require('console')
// 再绑定 文件流 和 输出流
const fs = require('fs')
const out = fs.createWriteStream('./tempOut.log')
const err = fs.createWriteStream('./tempErr.log')
const logger = new Console({ stdout: out, stderr: err })

logger.info('info...')
// trace 输出 堆栈跟踪打印到代码中的当前位置
logger.trace('trace....')
logger.error('error...')
logger.table([{ a: 1, b: 2, c: 3 },{ a: 1, b: 2, c: 3 },{ a: 1, b: 2, c: 3 }])

然后就能得到两个文件tempOut.logtempErr.log

tempOut.log 内容如下

info...
┌─────────┬───┬───┬───┐
│ (index) │ a │ b │ c │
├─────────┼───┼───┼───┤
│ 0 │ 1 │ 2 │ 3 │
│ 1 │ 1 │ 2 │ 3 │
│ 2 │ 1 │ 2 │ 3 │
└─────────┴───┴───┴───┘

tempErr.log 内容

Trace: trace....
at Object.<anonymous> (d:\javaScript_Project\studyExpress\01.js:10:8)
at Module._compile (internal/modules/cjs/loader.js:1158:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)
at Module.load (internal/modules/cjs/loader.js:1002:32)
at Function.Module._load (internal/modules/cjs/loader.js:901:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
at internal/main/run_main_module.js:18:47
error...

异常处理

参考资料 中文文档--Error 参考资料 bin5i--Node.js 基础入门课程异常处理

异常处理主要分下面三类

同步异常处理 异步异常处理 全局异常处理

同步异常处理

let f= ()=>{
// 这里会报一个 x 未定义的异常
x++;
}

try {
f()
} catch (error) {
console.log('捕获的异常: ' + error.message)

// 也可以捕获后再抛出去
throw Error('未定义异常:' + error.message)
}

uncaughtException 事件

当有未捕获的异常抛出时,可以用这个做最后的补救

参数: err <Error> 未捕获的异常 origin <string> 这个参数可以不添加 标明异常的 来源

process.on('uncaughtException', (err, origin) => {
fs.writeSync(
process.stderr.fd,
`捕获的异常: ${err}\n` +
`异常的来源: ${origin}`
);
// 再执行退出函数
// 0 表示正常退出
// 1 使用失败代码退出
process.exit(1)
});

setTimeout(() => {
console.log('这里仍然会运行');
}, 500);

// 故意引起异常,但不要捕获它。
nonexistentFunc();
console.log('这里不会运行');

异步函数异常处理

参考资料 syaning--异步编程中的异常处理

为什么无法直接捕获到异步函数的错误

这是因为异步调用是立即返回的(指加入队列,等下一个宏任务执行完才执行),因此当发生异常的时候,已经脱离了 try..catch.. 的上下文了,所以异常无法直接被捕获。

CallBack 方式处理异常

CallBack 无法使用 try..catch.. 来捕获异常,而是通过在回调函数内部 手动处理异常,然后一层层的回调

使用 setTimeout 来模拟异步函数, 下面就是一个多异步操作串行的例子

function async(callback) {
setTimeout(function() {
var rand = Math.random();

if (rand < 0.2) {
callback('async error');
} else {
callback(null, rand);
}
}, 1000);
}

// 回调函数一层嵌一层,而且每一层都要判读是否出错。不仅代码可读性差,维护起来也非常不
async(function(err, result) {
if (err) {
console.log('失败:', err);
} else {
console.log('成功:', result);

async(function(err, result) {
if (err) {
console.log('失败:', err);
} else {
console.log('成功:', result);

async(function(err, result) {
if (err) {
console.log('失败:', err);
} else {
console.log('成功:', result);
}
});
}
});
}
});

这里 err 作为回调函数的第一个参数,如果 async 调用成功,则 err 为一个 false 值(可以是 nullundefined 等,在该例子中使用 null 这些都表示 0 即 false);如果 async 调用失败,则 err 为抛出的异常。当调用回调函数的时候,先判断 err 是否为 false 。如果为 false,则进行异常处理;否则执行成功的回调。

Promise 方式处理异常

Promise 的多异步操作串行有点绕,但是捕获异常只需使用 try-catch 就行了

function async() {
return new Promise((resolve, reject) => {
setTimeout(() => {
var rand = Math.random();

if (rand < 0.2) {
// 错误
reject('async error');
} else {
// 成功
resolve(rand);
}
}, 1000);
})
}

function onResolved(result) {
console.log('执行成功:', result);
}

function onRejected(err) {
console.log('失败:', err);
}

// 交替执行 async() 和 onResolved(result)
async().then(onResolved)
.then(async)
.then(onResolved)
.then(async)
.then(onResolved)
.catch(onRejected);